#!/usr/bin/perl
my $Version;
use warnings;
use strict;

#    Password Setter for Pete's Automated VGAP Hosting Thingy
#    Copyright (C) 1997-2004 Peter Harris
$    Version = '0.4.0';
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License version 2 as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    This program is currently hosted at http://www.agamemnon.net/vgap/

use Config::IniFiles;
use Digest::SHA1 'sha1_base64';
use Cwd;

our $ininame;
our $mainini;
our ($NumberOfGames,@ini);
our %UnShortName;

sub GetSalt {
   my $game = shift;
   my $salt = $ini[$game]->val('General','Salt');
   if (!defined($salt)) {
      $salt = '';
      $salt .= ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64] foreach(1..8);
      $ini[$game]->newval('General','Salt',$salt);
      UpdateConfig($game);
   }
   return $salt;
}

sub GenerateCookie {
   my $game = shift;
   my $type = shift;
   my $email = shift;
   my $salt = GetSalt($game);

   return sha1_base64($salt, $type, $email);

   # A crypt based implementation would probably want to
   # use <the first letter of $type>.$email , $salt
   # And then trim the first two letters (the salt) from
   # the front of the digest before returning it.
}

sub HashPassword($$) {
   my $game = shift;
   my $pass = shift;

   defined($game) or return sha1_base64('SysadminPasswordSalt','Password',$pass);

   return GenerateCookie($game, 'Password', $pass);
}

sub UpdateConfig($) {
   my $game = shift;
   my $gameini = $mainini->val('GameINI',"Game$game");

   $ini[$game]->RewriteConfig() or die("Cannot write new $gameini because:\n$!\n");
}

sub IniLoad {
   -e $ininame or die ("Can't open $ininame.\n");

   $mainini = new Config::IniFiles( -file => $ininame ) or die("Cannot open $ininame because:\n$!\n");

   $NumberOfGames= $mainini->val('General','NumberOfGames');
   return unless ($NumberOfGames >= 1);

   foreach my $game (1..$NumberOfGames) {

      my $gameini= $mainini->val('GameINI',"Game$game");
      $ini[$game]=new Config::IniFiles( -file => $gameini ) or die("Cannot open $gameini\n");

      $UnShortName{lc($ini[$game]->val('General','ShortName'))}=$game;
   }
}

sub Usage() {
   die "Usage: setvpass.pl [mainini] game:password:user\n";
}

$ininame = 'vgapd.ini';
Usage() if (!defined $ARGV[0]);
$ininame = shift(@ARGV) if (-e $ARGV[0]);
Usage() if (!defined $ARGV[0]);

IniLoad;

my ($game, $user, $pass, $authgame);

($game,$pass,$user)=split /:/,$ARGV[0];
Usage() if (!defined $user);

if ($user eq 'sysadmin') {
   $mainini->setval('General','SysadminPW',HashPassword(undef,$pass));
   $mainini->RewriteConfig() or die("Cannot write new $ininame because:\n$!\n");
   print("Setting Sysadmin Password.\n");
} elsif ($user eq 'admin') {
   $authgame=$UnShortName{lc($game)};
   if (defined $authgame) {
      $ini[$authgame]->setval('Admin','Password',HashPassword($authgame,$pass));
      UpdateConfig($authgame);
      print "Setting Password for admin of $game\n";
   } else {
      die "Game $game does not exist\n";
   }
} else {
   $user =~ s/^a$/10/i;
   $user =~ s/^b$/11/i;
   $authgame=$UnShortName{lc($game)};
   die("Game $game does not exist\n") if (!defined($authgame));
   die("Invalid user: $user\n") if ($user < 1 || $user > 11);
   die("Inactive user: $user\n") if (uc($ini[$authgame]->val("Player$user",'Active')) eq 'NO');
   $ini[$authgame]->setval("Player$user",'Password',HashPassword($authgame,$pass));
   UpdateConfig($authgame);
   print "Setting Password for player $user of $game\n";
}
